#include <stdlib.h>
#include <glib.h>
#include <gtk/gtk.h>
#include <SDL.h>
#include "racanhack.h"
#include "task.h"
#include "video.h"
#include "cave.h"
#include "player.h"
#include "monster2.h"
#include "object.h"
#include "object2.h"
#include "floor.h"
#include "main.h"

struct _object_info {
  int type;
  gchar ident_name[OBJECT_NAME_MAX_LENGTH];
  gchar unident_name[OBJECT_NAME_MAX_LENGTH];
  gboolean ident;
  int atk;
  int ac;
  int prob;
};

struct _prob_table {
  int total;
  int start_id;
  int end_id;
};

static struct _object_info object_info[OBJECT_ID_MAX];
static struct _prob_table prob_table[OBJECT_TYPE_MAX];

static int object_calc_id(struct _object *object);
static int object_calc_plus(struct _object *object);
static int object_calc_count(struct _object *object);
static int qsort_shuffle(const int *a, const int *b);
static void init_object_info(int id, int type, gchar *ident_name, gchar *unident_name, int atk, int ac, int prob);
static void weapon_init();
static void shield_init();
static void arrow_init();
static void ring_init();
static void potion_init();
static void scroll_init();
static void wand_init();
static void food_init();
static void extra_init();

guint damage_calc_wielded(struct _monster *monster, struct _object *object, struct _player *player)
{
  guint d;
  int i;
  int ac;
  if (g_random_int_range(0, 8) == 0) return DODGED_DAMAGE;
  d = player->atk + ((player->atk * (object_atk(object) + player->cstr - 8)) / 16);
  d *= g_random_int_range(112, 143);
  ac = monster_ac(monster);
  for (i = 0; i < ac; i++) {
    d -= (d / 16);
  };
  d /= 128;
  if (d <= 0) d = DODGED_DAMAGE;
  return d;
}

guint damage_calc_throwed(struct _monster *monster, struct _object *object, struct _player *player)
{
  guint d;
  int i;
  int ac;
  if (g_random_int_range(0, 8) == 0) return DODGED_DAMAGE;
  d = player->atk + ((player->atk * (object_atk(object) - 8)) / 16);
  d *= g_random_int_range(112, 143);
  ac = monster_ac(monster);
  for (i = 0; i < ac; i++) {
    d -= (d / 16);
  };
  d /= 128;
  if (d <= 0) d = DODGED_DAMAGE;
  return d;
}

guint damage_calc_attacked_by_monster(struct _monster *monster, struct _object *object, struct _player *player)
{
  guint d;
  int i;
  int ac;
  if (g_random_int_range(0, 8) == 0) return DODGED_DAMAGE;
  d = monster_atk(monster);
  d *= g_random_int_range(112, 143);
  ac = object_ac(object);
  for (i = 0; i < ac; i++) {
    d -= (d / 16);
  };
  d /= 128;
  if (d <= 0) d = DODGED_DAMAGE;
  return d;
}

gboolean can_takeoff(struct _object *object, struct _player *player)
{
  if ((object == player->weapon) &&
      (object_cursed(player->weapon))) return FALSE;
  if ((object == player->shield) &&
      (object_cursed(player->shield))) return FALSE;
  if ((object == player->arrow) &&
      (object_cursed(player->arrow)))  return FALSE;
  if ((object == player->ring) &&
      (object_cursed(player->ring))) return FALSE;
  return TRUE;
}

void takeoff(struct _object *object, struct _player *player)
{
  if (object == player->weapon) {
    msg("You have taken off %s.", object_name(player->weapon));
    equip(&Noweapon, player);
    return;
  };
  if (object == player->shield) {
    msg("You have taken off %s.", object_name(player->shield));
    equip(&Noshield, player);
    return;
  };
  if (object == player->arrow) {
    msg("You have taken off the quiver of %s.", object_name(player->arrow));
    equip(&Noarrow, player);
    return;
  };
  if (object == player->ring) {
    if (player->ring->id == OBJECT_ID_STRENGTH_RING) {
      player->mstr = CLAMP(player->mstr  - player->ring->plus, 0, G_MAXINT);
      player->cstr = CLAMP(player->cstr - player->ring->plus, 0, player->mstr);
    };
    msg("You have taken off %s.", object_name(player->ring));
    equip(&Noring, player);
    return;
  };
}

void equip(struct _object *object, struct _player *player)
{
  switch (object_type(object)) {
  case OBJECT_TYPE_WEAPON:
    player->weapon = object;
    break;
  case OBJECT_TYPE_SHIELD:
    player->shield = object;
    break;
  case OBJECT_TYPE_ARROW:
    player->arrow = object;
    break;
  case OBJECT_TYPE_RING:
    player->ring = object;
    if (object->id == OBJECT_ID_STRENGTH_RING) {
      player->mstr = CLAMP(player->mstr + object->plus, 0, G_MAXINT);
      player->cstr = CLAMP(player->cstr + object->plus, 0, player->mstr);
    };
    break;
  };
  if ((object->id != OBJECT_ID_NOWEAPON) &&
      (object->id != OBJECT_ID_NOSHIELD) &&
      (object->id != OBJECT_ID_NOARROW) &&
      (object->id != OBJECT_ID_NORING)) {
    msg("You equiped %s.", object_name(object));
  };
}

static int object_calc_id(struct _object *object)
{
  int r;
  int type;
  int id;
  r = g_random_int_range(0, 20);
  switch(r) {
  case 0:
  case 1:
    type = OBJECT_TYPE_WEAPON;
    break;
  case 2:
  case 3:
    type = OBJECT_TYPE_SHIELD;
    break;
  case 4:
  case 5:
    type = OBJECT_TYPE_ARROW;
    break;
  case 6:
  case 7:
    type = OBJECT_TYPE_RING;
    break;
  case 8:
  case 9:
  case 10:
  case 11:
    type = OBJECT_TYPE_POTION;
    break;
  case 12:
  case 13:
  case 14:
  case 15:
  case 16:
  case 17:
    type = OBJECT_TYPE_SCROLL;
    break;
  case 18:
    type = OBJECT_TYPE_WAND;
    break;
  case 19:
    type = OBJECT_TYPE_FOOD;
    break;
  default:
    g_assert_not_reached();
    break;
  };
  r = g_random_int_range(0, prob_table[type].total);
  for (id = prob_table[type].start_id; id <= prob_table[type].end_id; id++) {
    if (id == prob_table[type].end_id) break;
    if (r < object_info[id + 1].prob) break;
  };
  return id;
}

static int object_calc_plus(struct _object *object)
{
  int p;
  switch(object_type(object)) {
  case OBJECT_TYPE_WEAPON:
  case OBJECT_TYPE_SHIELD:
    p = g_random_int_range(0, 100);
    if (p < 2) return -2;
    if (p < 5) return -1;
    if (p < 94) return 0;
    if (p < 98) return 1;
    if (p < 100) return 2;
    g_assert_not_reached();
    break;
  case OBJECT_TYPE_RING:
    if (object->id == OBJECT_ID_STRENGTH_RING) {
      p = g_random_int_range(0, 2);
      if (p == 0) return -3;
      if (p == 1) return 3;
      g_assert_not_reached();
    };
    p = g_random_int_range(0, 10);
    if (p < 3) return -1;
    if (p < 10) return 0;
    g_assert_not_reached();
    break;
  };
  return 0;
};

static int object_calc_count(struct _object *object)
{
  switch (object_type(object)) {
  case OBJECT_TYPE_ARROW:
    return g_random_int_range(1, 8);
  case OBJECT_TYPE_WAND:
    return g_random_int_range(1, 4);
  };
  return 0;
};

struct _object *object_add()
{
  struct _object *object;
  object = my_new(struct _object, 1);
  object->id = object_calc_id(object);
  object->coord = rand_coord();
  object->plus = object_calc_plus(object);
  object->count = object_calc_count(object);
  object->sprite = NULL;
  object->task = NULL;
  curf->object_list = g_list_append(curf->object_list, object);
  return (object);
}

struct _object *object_add_monsterhouse(struct _coord c)
{
  struct _object *object;
  object = my_new(struct _object, 1);
  object->id = object_calc_id(object);
  object->coord = c;
  object->plus = object_calc_plus(object);
  object->count = object_calc_count(object);
  object->sprite = NULL;
  object->task = NULL;
  curf->object_list = g_list_append(curf->object_list, object);
  return (object);
}

struct _object *object_add_specify_id(int id)
{
  struct _object *object;
  object = my_new(struct _object, 1);
  object->id = id;
  object->coord = rand_coord();
  object->plus = object_calc_plus(object);
  object->count = object_calc_count(object);
  object->sprite = NULL;
  object->task = NULL;
  curf->object_list = g_list_append(curf->object_list, object);
  return (object);
}

struct _object *arrow_add_from_quiver(struct _object *arrow_src)
{
  struct _object *arrow;
  arrow = my_new(struct _object, 1);
  arrow->id = arrow_src->id;
  arrow->coord = arrow_src->coord;
  arrow->plus = arrow_src->plus;
  arrow->count = 1;
  arrow->sprite = video_sprite_add(Z_ORDER_OBJECT);
  arrow->task = NULL;
  curf->object_list = g_list_append(curf->object_list, arrow);
  return (arrow);
}

struct _object *noweapon_add()
{
  struct _object *noweapon;
  noweapon = &Noweapon;
  noweapon->id = OBJECT_ID_NOWEAPON;
  noweapon->plus = 0;
  noweapon->count = 0;
  noweapon->sprite = NULL;
  noweapon->task = NULL;
  return (noweapon);
}

struct _object *noshield_add()
{
  struct _object *noshield;
  noshield = &Noshield;
  noshield->id = OBJECT_ID_NOSHIELD;
  noshield->plus = 0;
  noshield->count = 0;
  noshield->sprite = NULL;
  noshield->task = NULL;
  return (noshield);
}

struct _object *noarrow_add()
{
  struct _object *noarrow;
  noarrow = &Noarrow;
  noarrow->id = OBJECT_ID_NOARROW;
  noarrow->plus = 0;
  noarrow->count = 0;
  noarrow->sprite = NULL;
  noarrow->task = NULL;
  return (noarrow);
}

struct _object *noring_add()
{
  struct _object *noring;
  noring = &Noring;
  noring->id = OBJECT_ID_NORING;
  noring->plus = 0;
  noring->count = 0;
  noring->sprite = NULL;
  noring->task = NULL;
  return (noring);
}

void set_object_ident(struct _object *object, gboolean ident)
{
  object_info[object->id].ident = ident;
}

gboolean object_type(struct _object *object)
{
  return object_info[object->id].type;
}

gchar *object_name(struct _object *object)
{
  if (object_info[object->id].ident)
    return object_info[object->id].ident_name;
  return object_info[object->id].unident_name;
}

gboolean object_ident(struct _object *object)
{
  return object_info[object->id].ident;
}

int object_atk(struct _object *object)
{
  int atk;
  int plus;
  atk = object_info[object->id].atk;
  plus = object->plus;
  return (atk + plus);
}

int object_ac(struct _object *object)
{
  int ac;
  int plus;
  ac = object_info[object->id].ac;
  plus = object->plus;
  return (ac + plus);
}

gboolean object_cursed(struct _object *object)
{
  if (object->plus < 0) return TRUE;
  return FALSE;
};

void object_init()
{
  SDL_Surface *s;
  SDL_Rect r;
  int i;
  r.x = 0; r.y = 0;
  r.w = SPRITE_W; r.h = SPRITE_H;
  s = video_bmp_load("bmp/weapon_on_floor.bmp");
  surface_object_on_floor[OBJECT_TYPE_WEAPON] = video_crop(s, &r);
  SDL_FreeSurface(s);
  s = video_bmp_load("bmp/shield_on_floor.bmp");
  surface_object_on_floor[OBJECT_TYPE_SHIELD] = video_crop(s, &r);
  SDL_FreeSurface(s);
  s = video_bmp_load("bmp/arrow_on_floor.bmp");
  surface_object_on_floor[OBJECT_TYPE_ARROW] = video_crop(s, &r);
  SDL_FreeSurface(s);
  s = video_bmp_load("bmp/ring_on_floor.bmp");
  surface_object_on_floor[OBJECT_TYPE_RING] = video_crop(s, &r);
  SDL_FreeSurface(s);
  s = video_bmp_load("bmp/potion_on_floor.bmp");
  surface_object_on_floor[OBJECT_TYPE_POTION] = video_crop(s, &r);
  SDL_FreeSurface(s);
  s = video_bmp_load("bmp/scroll_on_floor.bmp");
  surface_object_on_floor[OBJECT_TYPE_SCROLL] = video_crop(s, &r);
  SDL_FreeSurface(s);
  s = video_bmp_load("bmp/wand_on_floor.bmp");
  surface_object_on_floor[OBJECT_TYPE_WAND] = video_crop(s, &r);
  SDL_FreeSurface(s);
  s = video_bmp_load("bmp/food_on_floor.bmp");
  surface_object_on_floor[OBJECT_TYPE_FOOD] = video_crop(s, &r);
  SDL_FreeSurface(s);
  s = video_bmp_load("bmp/extra_on_floor.bmp");
  surface_object_on_floor[OBJECT_TYPE_EXTRA] = video_crop(s, &r);
  SDL_FreeSurface(s);
  r.x = 0; r.y = 0;
  s = video_bmp_load("bmp/magic.bmp");
  surface_magic[0] = video_crop(s, &r);
  r.x = SPRITE_W; r.y = 0;
  surface_magic[1] = video_crop(s, &r);
  SDL_FreeSurface(s);
  for (i = 0; i < OBJECT_TYPE_MAX; i++) prob_table[i].total = 0;
  weapon_init();
  shield_init();
  arrow_init();
  ring_init();
  potion_init();
  scroll_init();
  wand_init();
  food_init();
  extra_init();
}

void object_free()
{
  int i;
  for (i = 0; i < OBJECT_TYPE_MAX; i++) {
    SDL_FreeSurface(surface_object_on_floor[i]);
  };
}

static int qsort_shuffle(const int *a, const int *b)
{
  return g_random_int_range(-1, 2);
}

static void init_object_info(int id, int type, gchar *ident_name, gchar *unident_name, int atk, int ac, int prob)
{
  object_info[id].type = type;
  g_snprintf(object_info[id].ident_name, OBJECT_NAME_MAX_LENGTH, "%s", ident_name);
  if (unident_name == NULL) {
    object_info[id].ident = TRUE;
    g_snprintf(object_info[id].unident_name, OBJECT_NAME_MAX_LENGTH, "NULL");
  } else {
    object_info[id].ident = FALSE;
    g_snprintf(object_info[id].unident_name, OBJECT_NAME_MAX_LENGTH, "%s", unident_name);
  };
  object_info[id].atk = atk;
  object_info[id].ac = ac;
  object_info[id].prob = prob_table[type].total;
  prob_table[type].total += prob;
}

static void weapon_init()
{
  prob_table[OBJECT_TYPE_WEAPON].start_id = OBJECT_ID_NOWEAPON;
  prob_table[OBJECT_TYPE_WEAPON].end_id = OBJECT_ID_TWOHSWORD;
  init_object_info(OBJECT_ID_NOWEAPON, OBJECT_TYPE_WEAPON, "no weapon", NULL, 0, 0, 0);
  init_object_info(OBJECT_ID_DAGGER, OBJECT_TYPE_WEAPON, "dagger", NULL, 1, 0, 8);
  init_object_info(OBJECT_ID_MACE, OBJECT_TYPE_WEAPON, "mace", NULL, 2, 0, 5);
  init_object_info(OBJECT_ID_LONGSWORD, OBJECT_TYPE_WEAPON, "longsword", NULL, 4, 0, 2);
  init_object_info(OBJECT_ID_TWOHSWORD, OBJECT_TYPE_WEAPON, "twohsword", NULL, 6, 0, 1);
}

static void shield_init()
{
  prob_table[OBJECT_TYPE_SHIELD].start_id = OBJECT_ID_NOSHIELD;
  prob_table[OBJECT_TYPE_SHIELD].end_id = OBJECT_ID_DWARVISH_SHIELD;
  init_object_info(OBJECT_ID_NOSHIELD, OBJECT_TYPE_SHIELD, "no shield", NULL, 0, 0, 0);
  init_object_info(OBJECT_ID_SMALL_SHIELD, OBJECT_TYPE_SHIELD, "small shield", NULL, 0, 2, 8);
  init_object_info(OBJECT_ID_ORCISH_SHIELD, OBJECT_TYPE_SHIELD, "orcish shield", NULL, 0, 3, 6);
  init_object_info(OBJECT_ID_ELVEN_SHIELD, OBJECT_TYPE_SHIELD, "elven shield", NULL, 0, 4, 4);
  init_object_info(OBJECT_ID_LARGE_SHIELD, OBJECT_TYPE_SHIELD, "large shield", NULL, 0, 5, 3);
  init_object_info(OBJECT_ID_DWARVISH_SHIELD, OBJECT_TYPE_SHIELD, "dwarvish shield", NULL, 0, 6, 1);
}

static void arrow_init()
{
  prob_table[OBJECT_TYPE_ARROW].start_id = OBJECT_ID_NOARROW;
  prob_table[OBJECT_TYPE_ARROW].end_id = OBJECT_ID_IRON_ARROW;
  init_object_info(OBJECT_ID_NOARROW, OBJECT_TYPE_ARROW, "no arrow", NULL, 0, 0, 0);
  init_object_info(OBJECT_ID_WOOD_ARROW, OBJECT_TYPE_ARROW, "wooden arrow", NULL, 4, 0, 5);
  init_object_info(OBJECT_ID_IRON_ARROW, OBJECT_TYPE_ARROW, "iron arrow", NULL, 12, 0, 1);
}

static void ring_init()
{
  enum {C = 15};
  int i;
  int table[C];
  gchar buf[C][OBJECT_NAME_MAX_LENGTH];
  for (i = 0; i < C; i++) table[i] = i;
  qsort(table, C, sizeof(int), (int(*)(const void*, const void*))qsort_shuffle);
  g_snprintf(buf[0], OBJECT_NAME_MAX_LENGTH, "green ring");
  g_snprintf(buf[1], OBJECT_NAME_MAX_LENGTH, "yellow ring");
  g_snprintf(buf[2], OBJECT_NAME_MAX_LENGTH, "red ring");
  g_snprintf(buf[3], OBJECT_NAME_MAX_LENGTH, "white ring");
  g_snprintf(buf[4], OBJECT_NAME_MAX_LENGTH, "blue ring");
  g_snprintf(buf[5], OBJECT_NAME_MAX_LENGTH, "black ring");
  g_snprintf(buf[6], OBJECT_NAME_MAX_LENGTH, "purple ring");
  g_snprintf(buf[7], OBJECT_NAME_MAX_LENGTH, "gray ring");
  g_snprintf(buf[8], OBJECT_NAME_MAX_LENGTH, "pink ring");
  g_snprintf(buf[9], OBJECT_NAME_MAX_LENGTH, "orange ring");
  g_snprintf(buf[10], OBJECT_NAME_MAX_LENGTH, "cyan ring");
  g_snprintf(buf[11], OBJECT_NAME_MAX_LENGTH, "bronze ring");
  g_snprintf(buf[12], OBJECT_NAME_MAX_LENGTH, "copper ring");
  g_snprintf(buf[13], OBJECT_NAME_MAX_LENGTH, "silver ring");
  g_snprintf(buf[14], OBJECT_NAME_MAX_LENGTH, "indigo ring");
  prob_table[OBJECT_TYPE_RING].start_id = OBJECT_ID_NORING;
  prob_table[OBJECT_TYPE_RING].end_id = OBJECT_ID_ADORNMENT_RING;
  init_object_info(OBJECT_ID_NORING, OBJECT_TYPE_RING, "no ring", NULL, 0, 0, 0);
  init_object_info(OBJECT_ID_SLOWDIGEST_RING, OBJECT_TYPE_RING,  "ring of slow digestion",  buf[table[0]], 0, 0, 1);
  init_object_info(OBJECT_ID_FASTDIGEST_RING, OBJECT_TYPE_RING, "ring of fast digestion", buf[table[1]], 0, 0, 10);
  init_object_info(OBJECT_ID_STRENGTH_RING, OBJECT_TYPE_RING, "ring of strength",  buf[table[2]] ,0, 0, 6);
  init_object_info(OBJECT_ID_SLEEPLESS_RING, OBJECT_TYPE_RING, "ring of sleepless",  buf[table[3]] ,0, 0, 10);
  init_object_info(OBJECT_ID_ADORNMENT_RING, OBJECT_TYPE_RING, "ring of adornment",  buf[table[4]] ,0, 0, 10);
}

static void potion_init()
{
  enum {C = 15};
  int i;
  int table[C];
  gchar buf[C][OBJECT_NAME_MAX_LENGTH];
  for (i = 0; i < C; i++) table[i] = i;
  qsort(table, C, sizeof(int), (int(*)(const void*, const void*))qsort_shuffle);
  g_snprintf(buf[0], OBJECT_NAME_MAX_LENGTH, "green potion");
  g_snprintf(buf[1], OBJECT_NAME_MAX_LENGTH, "yellow potion");
  g_snprintf(buf[2], OBJECT_NAME_MAX_LENGTH, "red potion");
  g_snprintf(buf[3], OBJECT_NAME_MAX_LENGTH, "white potion");
  g_snprintf(buf[4], OBJECT_NAME_MAX_LENGTH, "blue potion");
  g_snprintf(buf[5], OBJECT_NAME_MAX_LENGTH, "black potion");
  g_snprintf(buf[6], OBJECT_NAME_MAX_LENGTH, "purple potion");
  g_snprintf(buf[7], OBJECT_NAME_MAX_LENGTH, "gray potion");
  g_snprintf(buf[8], OBJECT_NAME_MAX_LENGTH, "pink potion");
  g_snprintf(buf[9], OBJECT_NAME_MAX_LENGTH, "orange potion");
  g_snprintf(buf[10], OBJECT_NAME_MAX_LENGTH, "cyan potion");
  g_snprintf(buf[11], OBJECT_NAME_MAX_LENGTH, "bronze potion");
  g_snprintf(buf[12], OBJECT_NAME_MAX_LENGTH, "copper potion");
  g_snprintf(buf[13], OBJECT_NAME_MAX_LENGTH, "silver potion");
  g_snprintf(buf[14], OBJECT_NAME_MAX_LENGTH, "indigo potion");
  prob_table[OBJECT_TYPE_POTION].start_id = OBJECT_ID_HEAL_POTION;
  prob_table[OBJECT_TYPE_POTION].end_id = OBJECT_ID_RAISELEV_POTION;
  init_object_info(OBJECT_ID_HEAL_POTION, OBJECT_TYPE_POTION, "healing potion", buf[table[0]], 0, 0, 8);
  init_object_info(OBJECT_ID_INCSTR_POTION, OBJECT_TYPE_POTION,  "increase strength potion",  buf[table[1]], 0, 0, 6);
  init_object_info(OBJECT_ID_RESSTR_POTION, OBJECT_TYPE_POTION, "restore strength potion", buf[table[2]], 0, 0, 4);
  init_object_info(OBJECT_ID_POISON_POTION, OBJECT_TYPE_POTION, "poison potion",  buf[table[3]] ,0, 0, 8);
  init_object_info(OBJECT_ID_EXHEAL_POTION, OBJECT_TYPE_POTION, "extra healing potion",  buf[table[4]] ,0, 0, 4);
  init_object_info(OBJECT_ID_BLINDNESS_POTION, OBJECT_TYPE_POTION, "blindness potion",  buf[table[5]] ,0, 0, 6);
  init_object_info(OBJECT_ID_RAISELEV_POTION, OBJECT_TYPE_POTION, "raise level potion",  buf[table[6]] ,0, 0, 1);
}

static void scroll_init()
{
  enum {C = 15};
  int i;
  int table[C];
  gchar buf[C][OBJECT_NAME_MAX_LENGTH];
  for (i = 0; i < C; i++) table[i] = i;
  qsort(table, C, sizeof(int), (int(*)(const void*, const void*))qsort_shuffle);
  g_snprintf(buf[0], OBJECT_NAME_MAX_LENGTH, "green scroll");
  g_snprintf(buf[1], OBJECT_NAME_MAX_LENGTH, "yellow scroll");
  g_snprintf(buf[2], OBJECT_NAME_MAX_LENGTH, "red scroll");
  g_snprintf(buf[3], OBJECT_NAME_MAX_LENGTH, "white scroll");
  g_snprintf(buf[4], OBJECT_NAME_MAX_LENGTH, "blue scroll");
  g_snprintf(buf[5], OBJECT_NAME_MAX_LENGTH, "black scroll");
  g_snprintf(buf[6], OBJECT_NAME_MAX_LENGTH, "purple scroll");
  g_snprintf(buf[7], OBJECT_NAME_MAX_LENGTH, "gray scroll");
  g_snprintf(buf[8], OBJECT_NAME_MAX_LENGTH, "pink scroll");
  g_snprintf(buf[9], OBJECT_NAME_MAX_LENGTH, "orange scroll");
  g_snprintf(buf[10], OBJECT_NAME_MAX_LENGTH, "cyan scroll");
  g_snprintf(buf[11], OBJECT_NAME_MAX_LENGTH, "bronze scroll");
  g_snprintf(buf[12], OBJECT_NAME_MAX_LENGTH, "copper scroll");
  g_snprintf(buf[13], OBJECT_NAME_MAX_LENGTH, "silver scroll");
  g_snprintf(buf[14], OBJECT_NAME_MAX_LENGTH, "indigo scroll");
  prob_table[OBJECT_TYPE_SCROLL].start_id = OBJECT_ID_IDENT_SCROLL;
  prob_table[OBJECT_TYPE_SCROLL].end_id = OBJECT_ID_MAP_SCROLL;
  init_object_info(OBJECT_ID_IDENT_SCROLL, OBJECT_TYPE_SCROLL, "identify scroll", buf[table[0]], 0, 0, 6);
  init_object_info(OBJECT_ID_RMCURSE_SCROLL, OBJECT_TYPE_SCROLL, "remove curse scroll", buf[table[1]], 0, 0, 2);
  init_object_info(OBJECT_ID_ENCWEAPON_SCROLL, OBJECT_TYPE_SCROLL, "enchant weapon scroll", buf[table[2]], 0, 0, 3);
  init_object_info(OBJECT_ID_ENCSHIELD_SCROLL, OBJECT_TYPE_SCROLL, "enchant shield scroll", buf[table[3]], 0, 0, 3);
  init_object_info(OBJECT_ID_EXPLOSION_SCROLL, OBJECT_TYPE_SCROLL, "explosion scroll", buf[table[4]], 0, 0, 3);
  init_object_info(OBJECT_ID_MONDETECT_SCROLL, OBJECT_TYPE_SCROLL, "monster detect scroll", buf[table[5]], 0, 0, 3);
  init_object_info(OBJECT_ID_OBJDETECT_SCROLL, OBJECT_TYPE_SCROLL, "object detect scroll", buf[table[6]], 0, 0, 3);
  init_object_info(OBJECT_ID_CREATE_MON_SCROLL, OBJECT_TYPE_SCROLL, "create monster scroll", buf[table[7]], 0, 0, 4);
  init_object_info(OBJECT_ID_TELEPORT_SCROLL, OBJECT_TYPE_SCROLL, "teleportation scroll", buf[table[8]], 0, 0, 4);
  init_object_info(OBJECT_ID_MAP_SCROLL, OBJECT_TYPE_SCROLL, "map scroll", buf[table[9]], 0, 0, 3);
}

static void wand_init()
{
  enum {C = 15};
  int i;
  int table[C];
  gchar buf[C][OBJECT_NAME_MAX_LENGTH];
  for (i = 0; i < C; i++) table[i] = i;
  qsort(table, C, sizeof(int), (int(*)(const void*, const void*))qsort_shuffle);
  g_snprintf(buf[0], OBJECT_NAME_MAX_LENGTH, "green wand");
  g_snprintf(buf[1], OBJECT_NAME_MAX_LENGTH, "yellow wand");
  g_snprintf(buf[2], OBJECT_NAME_MAX_LENGTH, "red wand");
  g_snprintf(buf[3], OBJECT_NAME_MAX_LENGTH, "white wand");
  g_snprintf(buf[4], OBJECT_NAME_MAX_LENGTH, "blue wand");
  g_snprintf(buf[5], OBJECT_NAME_MAX_LENGTH, "black wand");
  g_snprintf(buf[6], OBJECT_NAME_MAX_LENGTH, "purple wand");
  g_snprintf(buf[7], OBJECT_NAME_MAX_LENGTH, "gray wand");
  g_snprintf(buf[8], OBJECT_NAME_MAX_LENGTH, "pink wand");
  g_snprintf(buf[9], OBJECT_NAME_MAX_LENGTH, "orange wand");
  g_snprintf(buf[10], OBJECT_NAME_MAX_LENGTH, "cyan wand");
  g_snprintf(buf[11], OBJECT_NAME_MAX_LENGTH, "bronze wand");
  g_snprintf(buf[12], OBJECT_NAME_MAX_LENGTH, "copper wand");
  g_snprintf(buf[13], OBJECT_NAME_MAX_LENGTH, "silver wand");
  g_snprintf(buf[14], OBJECT_NAME_MAX_LENGTH, "indigo wand");
  prob_table[OBJECT_TYPE_WAND].start_id = OBJECT_ID_TELEPORT_WAND;
  prob_table[OBJECT_TYPE_WAND].end_id = OBJECT_ID_SLEEP_WAND;
  init_object_info(OBJECT_ID_TELEPORT_WAND, OBJECT_TYPE_WAND, "teleport away wand", buf[table[0]], 0, 0, 1);
  init_object_info(OBJECT_ID_CONFUSE_WAND, OBJECT_TYPE_WAND, "confuse monster wand", buf[table[1]], 0, 0, 1);
  init_object_info(OBJECT_ID_MMISSILE_WAND, OBJECT_TYPE_WAND, "magic missile wand", buf[table[2]], 0, 0, 1);
  init_object_info(OBJECT_ID_SLEEP_WAND, OBJECT_TYPE_WAND, "sleep wand", buf[table[3]], 0, 0, 1);
}

static void food_init()
{
  prob_table[OBJECT_TYPE_FOOD].start_id = OBJECT_ID_RATION;
  prob_table[OBJECT_TYPE_FOOD].end_id = OBJECT_ID_SLIMEMOLD;
  init_object_info(OBJECT_ID_RATION, OBJECT_TYPE_FOOD, "ration", NULL, 0, 0, 1);
  init_object_info(OBJECT_ID_SLIMEMOLD, OBJECT_TYPE_FOOD, "slimemold", NULL, 0, 0, 1);
}

static void extra_init()
{
  prob_table[OBJECT_TYPE_EXTRA].start_id = OBJECT_ID_AMUYENDOR;
  prob_table[OBJECT_TYPE_EXTRA].end_id = OBJECT_ID_AMUYENDOR;
  init_object_info(OBJECT_ID_AMUYENDOR, OBJECT_TYPE_EXTRA, "amulet of yendor", NULL, 0, 0, 0);
}
 
